#include "ring_scaling.h"

RNSScaler::RNSScaler(Ring *ringQ, Ring *ringT) : ringQ(ringQ), ringT(ringT)
{
    polypoolQ = ringQ->NewPoly();
    polypoolT = ringT->NewPoly();

    uint64_t t = ringT->Modulus[0];

    qHalf = (*ringQ->modulusBigint) % t;
    qInv = qHalf.get_ui();

    qInv = InvMod(qInv, t);
    qHalf = *ringQ->modulusBigint;
    qHalf >>= 1;
    qHalf %= t;

    qHalfModT = qHalf.get_ui();

    qHalf = *ringQ->modulusBigint;
    qHalf >>= 1;
}
/*
 * @brief 将环Q上的多项式p1Q转换为环T上的多项式p2T。
 *
 * 该函数实现了将多项式 `p1Q`（基于 Q 的多项式）除以 t（模 T）并进行四舍五入的操作，得到结果多项式 `p2T`。
 *
 * @param p1Q 输入的基于 Q 的多项式。
 * @param p2T 输出的基于 T 的多项式，保存四舍五入后的除法结果。
 */
void RNSScaler::DivByQOverTRounded(Poly *p1Q, Poly *p2T)
{
    baseconverterQ1Q2 = new FastBasisExtender(ringT, ringQ);
    uint64_t T = ringT->Modulus[0];
    std::vector<uint64_t> &p2tmp = p2T->Coeffs[0];
    std::vector<uint64_t> &p3tmp = polypoolT->Coeffs[0];
    vector<uint64_t> mBredParams = ringT->bredParams[0];
    uint64_t tmpqInv = T - qInv;
    uint64_t tmpqHalfModT = T - qHalfModT;

    // Multiply P_{Q} by t and extend the basis from P_{Q} to t*(P_{Q}||P_{t})
    // Since the coefficients of P_{t} are multiplied by t, they are all zero,
    // hence the basis extension can be omitted
    ringQ->MulScalarBarrett(p1Q, T, polypoolQ);

    // Center t*P_{Q} around (Q-1)/2 to round instead of floor during the division
    ringQ->AddScalarBigint(polypoolQ, qHalf, polypoolQ);

    // Extend the basis of (t*P_{Q} + (Q-1)/2) to (t*P_{t} + (Q-1)/2)
    baseconverterQ1Q2->BaseConvertP2Q(ringT->Modulus.size() - 1, ringQ->Modulus.size() - 1, polypoolQ, polypoolT);
    // Compute [Q^{-1} * (t*P_{t} -   (t*P_{Q} - ((Q-1)/2 mod t)))] mod t which returns round(t/Q * P_{Q}) mod t
#pragma omp parallel for
    for (int j = 0; j < ringQ->N; j++) {
        MulModBarrett(p2tmp[j], tmpqHalfModT + p3tmp[j], tmpqInv, T, mBredParams[2], mBredParams[0], mBredParams[1]);
    }
}
